import time
import subprocess
import json

class TimeWheelTimer:

    def __init__(self, slot_interval, slot_count):
        """
        初始化时间轮
        :param slot_interval: 每个槽的时间间隔（秒）
        :param slot_count: 时间轮的槽数量
        """
        self.slot_interval = slot_interval
        self.slot_count = slot_count
        self.wheel = [[] for _ in range(slot_count)]  # 初始化时间轮槽
        self.current_slot = 0  # 当前指针位置
        self.last_tick_time = time.time()  # 上一次 tick 的时间

    def addTask(self, delay, task):
        """
        添加定时任务
        :param delay: 任务的延迟时间（秒）
        :param task: 任务函数
        """
        slots = (self.current_slot + delay // self.slot_interval) % self.slot_count
        self.wheel[slots].append(task)
        #DebugPrint(f"Task added to slot {slots}, will run in {delay} seconds.")

    def tick(self):
        """时间轮 tick 逻辑"""
        current_time = time.time()
        elapsed_time = current_time - self.last_tick_time

        # 如果经过的时间大于一个槽的间隔，则移动指针
        if elapsed_time >= self.slot_interval:
            steps = int(elapsed_time // self.slot_interval)
            for _ in range(steps):
                self.current_slot = (self.current_slot + 1) % self.slot_count
                tasks = self.wheel[self.current_slot]
                if tasks:
                    #DebugPrint(f"Slot {self.current_slot} triggered, running tasks...")
                    for task in tasks:
                        try:
                            task()  # 执行任务
                        except Exception as e:
                            DebugPrint(f"Task execution failed: {e}")
                    self.wheel[self.current_slot] = []  # 清空当前槽
            self.last_tick_time = current_time

    def run(self):
        """运行时间轮"""
        DebugPrint("Time wheel started.")
        try:
            while True:
                self.tick()
                time.sleep(0.1)  # 降低 CPU 占用
        except KeyboardInterrupt:
            DebugPrint("Time wheel stopped.")


class MuMuManager:
    def __init__(self):
        self._Executor = "MuMuManager.exe"
        self._allmachines = {}
        self._startupcb = []
        self._timewheel = TimeWheelTimer(1, 10)
        self._timewheel.addTask(1, self.CheckStartupResult)
        self._flagname = ""
        self._closeallskilllist = []

    def SetDefaultDeviceFlag(self, name):
        self._flagname = name

    def CheckStartupResult(self):
        #DebugPrint("Check startup result")
        if self._startupcb:
            dellist = []
            for name, cbfunc in self._startupcb:
                if self.CheckStartupFinished(name):
                    cbfunc()
                    dellist.append(name)
            for name in dellist:
                for tinfo in self._startupcb:
                    if tinfo[0] == name:
                        self._startupcb.remove(tinfo)
                        break
        self._timewheel.addTask(1, self.CheckStartupResult)

    def frame(self):
        self._timewheel.tick()

    def loadInfo(self):
        data = self.info("-v all")
        self._allmachines = json.loads(data)
        if "index" in self._allmachines:
            return {self._allmachines["index"]: self._allmachines}
        return self._allmachines

    def showAllDevices(self):
        for _, v in self.loadInfo().items():
            DebugPrint(v["name"])
    
    def getAllRunningDevices(self):
        devices = []
        for _, v in self.loadInfo().items():
            if "pid" not in v:
                continue
            devices.append(v["index"])
        return devices

    def GetIndexByHostInfo(self, host, port):
        for v in self.loadInfo().values():
            if "adb_host_ip" not in v:
                continue
            if "adb_port" not in v:
                continue
            if host == v["adb_host_ip"] and port == v["adb_port"]:
                return v["index"]
        return -1

    def GetIndexByName(self, name: str):
        for v in self.loadInfo().values():
            if name == v["name"]:
                return v["index"]
        return -1
    
    def getDeviceProcessID(self, name):
        for v in self.loadInfo().values():
            if name == v["name"]:
                if "headless_pid" not in v:
                    return 0
                return v["headless_pid"]
        return 0
    
    def ClientIsStillAlive(self, name):
        idx = self.GetIndexByName(name)
        r = g_MumuMgr.adb(f"-v {idx} shell ps")
        r = r.replace("com.lihoo.lihuo:", "")
        if "com.lihoo.lihuo" not in r:
            return False
        return True

    def executeCommand(self, op, cmds):
        if str == type(cmds):
            cmds = [self._Executor, op] + cmds.split(" ")
        elif type(cmds) in (tuple, list):
            cmds = [self._Executor, op] + cmds
        else:
            raise Exception(f"Unknow args: {type(cmds)}, {cmds}")
        result = subprocess.run(cmds, stdout=subprocess.PIPE)
        # 打印输出结果
        return result.stdout.decode("utf8")

    def info(self, args):
        result = self.executeCommand("info", args)
        return result

    def control(self, args):
        result = self.executeCommand("control", args)
        return result
    
    def adb(self, args):
        result = self.executeCommand("adb", args)
        return result
    
    #===========================================================

    def GetInfoByName(self, name: str):
        info = self.loadInfo()
        for v in info.values():
            if name == v["name"]:
                return v
        return dict()

    def GetDeviceADBPort(self, name: str):
        info = self.GetInfoByName(name)
        if not info:
            return 0
        if "adb_port" not in info:
            return 0
        return info["adb_port"]
    
    def GetDeviceHostIP(self, name: str):
        info = self.GetInfoByName(name)
        if not info:
            return ""
        if "adb_host_ip" not in info:
            return ""
        return info["adb_host_ip"]
    
    def GetDeviceSerialName(self, name):
        host = self.GetDeviceHostIP(name)
        port = self.GetDeviceADBPort(name)
        return f"{host}:{port}"

    def CheckStartupFinished(self, name: str):
        info = self.GetInfoByName(name)
        if not info:
            return False
        if "player_state" not in info:
            return False
        if "start_finished" != info["player_state"]:
            return False
        return True

    def startupDevice(self, name: str, cbfunc):
        index = self.GetIndexByName(name)
        if -1 == index:
            DebugPrint(f"device {name} not found.")
            return False
        self.control(f"-v {index} launch")
        self._startupcb.append((name, cbfunc))

    def restartDevice(self, name: str):
        index = self.GetIndexByName(name)
        if -1 == index:
            DebugPrint(f"device {name} not found.")
            return False
        self.control(f"-v {index} restart")
    
    def restartDeviceByHostInfo(self, host: str, port: int):
        index = self.GetIndexByHostInfo(host, port)
        if -1 == index:
            DebugPrint(f"device {host}:{port} not found.")
            return False
        self.control(f"-v {index} restart")

    def closeDevice(self, name: str):
        index = self.GetIndexByName(name)
        if -1 == index:
            DebugPrint(f"device {name} not found.")
            return False
        self.control(f"-v {index} shutdown")

    def closeAllDevices(self):
        for v in self.loadInfo().values():
            idx = v["index"]
            if v["name"] in self._closeallskilllist:
                # 这个不要关
                continue
            self.control(f"-v {idx} shutdown")
        return -1
    
    def AddDontCloseDevice(self, name):
        if name in self._closeallskilllist:
            return
        self._closeallskilllist.append(name)

    def getMonitorSize(self):
        import win32api
        # 获取所有显示器的信息
        monitors = win32api.EnumDisplayMonitors()
        for m in monitors:
            DebugPrint(m)
            # 获取每个显示器的信息（左、上、右、下）
            left, top, right, bottom = m[2]  # m[1] 是每个显示器区域的元组 (left, top, right, bottom)
            width = right - left
            height = bottom - top
            return width, height

    def sort(self):
        return
        w, h = self.getMonitorSize()
        if h > w:
            # 竖屏
            windowwidth = w / (len(devices) + 1)
            r = windowwidth / 1280.0
            windowheight = 720.0 * r
            devices = self.getAllRunningDevices()
            for step in range(len(devices)):
                idx = devices[step]
                x = step * windowwidth
                y = 0
                self.control(f"-v {idx} layout_window -px {x} -py {y} -sw {windowwidth} -sh {windowheight}")
        else:
            # 横屏
            devices = self.getAllRunningDevices()
            windowwidth = w / (len(devices) + 1)
            r = windowwidth / 1280.0
            windowheight = 720.0 * r
            for step in range(len(devices)):
                idx = devices[step]
                x = step * windowwidth
                y = 0
                self.control(f"-v {idx} layout_window -px {x} -py {y} -sw {windowwidth} -sh {windowheight}")
